#include "cexifsymbian.h"
#include <f32file.h>
#include <e32debug.h>
#include <exifread.h>
#include <exifmodify.h>
#include <exifutility.h>
#include <exiftag.h>

CExifSymbian::CExifSymbian(ExifHandler& aPublicAPI):
    CActive(EPriorityStandard),
    iPublicAPI(aPublicAPI),
    iState(ENothing)
{
    CActiveScheduler::Add(this);
}

CExifSymbian* CExifSymbian::NewL(ExifHandler& aPublicAPI)
{
    CExifSymbian* self = new (ELeave) CExifSymbian(aPublicAPI);
    CleanupStack::PushL(self);
    self->ConstructL();
    CleanupStack::Pop(self);
    return self;
}

CExifSymbian::~CExifSymbian()
{
    Cancel();
}

void CExifSymbian::LoadGPSPosition(const TDesC& aFilename)
{
    iFilename = aFilename;
    Cancel();
    iState = ELoadGPSPosition;
    iStatus = KRequestPending;
    SetActive();
    TRequestStatus* status = &iStatus;
    User::RequestComplete(status, KErrNone);
}

void CExifSymbian::ConstructL()
{

}

void CExifSymbian::DoCancel()
{
    TRequestStatus* status = &iStatus;
    User::RequestComplete(status, KErrCancel);
}

void CExifSymbian::RunL()
{
    switch(iState){
    case ELoadGPSPosition:{
        RFile file;
        RFs fs;
        TInt error = 0;
        TReal64 m_longitude = 0;
        TReal64 m_latitude = 0;
        TInt tags;
        TUint16* ptr = NULL;
        TBool longitude = ETrue;
        TBool west=ETrue;
        TBool north = ETrue;

        User::LeaveIfError(fs.Connect());
        User::LeaveIfError( file.Open( fs, iFilename, EFileRead ) );
        CleanupClosePushL( file );
        TInt size = 0;
        file.Size(size);

        // Don�t read more than 64k
        if ( size > 65536 )
            size = 65536;
        HBufC8* exif = HBufC8::NewL( size );
        CleanupStack::PushL( exif );
        TPtr8 bufferDes( exif->Des() );
        User::LeaveIfError( file.Read( bufferDes, size ) );
        CleanupStack::Pop( exif );
        CleanupStack::PopAndDestroy();
        CleanupStack::PushL( exif );

        CExifRead* read = CExifRead::NewL( exif->Des(),CExifRead::ENoTagChecking | CExifRead::ENoJpeg );
        CleanupStack::PushL( read );

        if(read->IfdExists(EIfdGps)){
            TRAP(error, ptr = read->GetTagIdsL(EIfdGps,tags));
            if(error==KErrNone && ptr!=NULL){

                for(TInt i=1;i<5;i++){
                    const CExifTag* tag = read->GetTagL(EIfdGps,ptr[i]);

                    if(tag){
                        switch(tag->TagInfo().iDataType)
                        {
                        case CExifTag::ETagAscii:
                        {
                            TBuf8<20> tmp;
                            tmp.CopyLC(tag->Data());
                            if(tmp.Find(_L8("n"))!=KErrNotFound || tmp.Find(_L8("s"))!=KErrNotFound ){
                                longitude = EFalse;
                                if(tmp.Find(_L8("n"))!=KErrNotFound)
                                    north = ETrue;
                                else if(tmp.Find(_L8("s")))
                                    north = EFalse;
                            }else{
                                longitude = ETrue;
                                if(tmp.Find(_L8("w"))!=KErrNotFound)
                                    west = ETrue;
                                else if(tmp.Find(_L8("e")))
                                    west = EFalse;
                            }
                        }break;

                        case CExifTag::ETagRational:
                        {
                            TReal64 num = 0;
                            TInt tmpData;
                            TReal64 numerator = 0;
                            TReal64 denominator = 0;
                            const TUint8* rationalData = tag->Data().Ptr();
                            for(TUint c=0;c<tag->TagInfo().iDataCount;c++){
                                numerator = 0;
                                denominator = 0;
                                Mem::Copy(&tmpData, rationalData + ((c * 2) * sizeof(tmpData)), sizeof(tmpData));
                                numerator = tmpData;
                                tmpData = 0;
                                Mem::Copy(&tmpData, rationalData + (((c * 2) + 1) * sizeof(tmpData)), sizeof(tmpData));
                                denominator = tmpData;

                                switch(c){
                                case 0:{
                                    num = (numerator/denominator);
                                    if(longitude)
                                        m_longitude = m_longitude + num;
                                    else
                                        m_latitude = m_latitude + num;
                                }break;
                                case 1:{
                                    num = (numerator/ denominator)/60;
                                    if(longitude)
                                        m_longitude = m_longitude + num;
                                    else
                                        m_latitude = m_latitude + num;
                                }break;
                                case 2:{
                                    num = (numerator/ denominator)/3600;
                                    if(longitude)
                                        m_longitude = m_longitude + num;
                                    else
                                        m_latitude = m_latitude + num;
                                }break;
                                default:break;
                                }
                            }
                        }break;

                        case CExifTag::ETagByte:
                        case CExifTag::ETagShort:
                        case CExifTag::ETagLong:
                        case CExifTag::ETagSlong:
                        case CExifTag::ETagSrational:
                        case CExifTag::ETagUndefined:
                        default:
                            break;
                        }
                    }
                }
                delete ptr;
            }
        }

        CleanupStack::PopAndDestroy( read );
        CleanupStack::PopAndDestroy( exif );
        iState = ENothing;
        if(west)
            m_longitude = m_longitude*-1;
        if(!north)
            m_latitude = m_latitude*-1;
        QT_TRYCATCH_LEAVING(emit iPublicAPI.gpsPosition(error,m_longitude,m_latitude);)
    }break;
    default:break;
    }
}
